package com.googlecode.cannedbeans.generator.util;

import com.googlecode.cannedbeans.generator.core.exceptions.UnsupportedClassException;
import com.googlecode.cannedbeans.generator.model.Clazz;
import com.googlecode.cannedbeans.generator.model.Property;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.beanutils.PropertyUtilsBean;

/**
 * 
 * @author Kim
 */
public class DefaultClazzBuilderImpl implements ClazzBuilder {
    /*
     * type and constraint mapping should probably be delegated to other classes, since the logic behind it might get complex.
     * TypeMapper.getType(Class classToMap).
     * */
    private TypeMapper typeMapper;
    private ConstraintExtractor constraintExtractor;
    private AnnotationExtractor annotationExtractor;

    public DefaultClazzBuilderImpl() {
    }

    public Clazz build(Class bean) throws UnsupportedClassException{
        Clazz clazz = new Clazz();
        PropertyUtilsBean pub = new PropertyUtilsBean();
        PropertyDescriptor[] descriptors = pub.getPropertyDescriptors(bean);
        for (PropertyDescriptor descriptor : descriptors) {
            Collection<Annotation> annotations = null;
            try {
                annotations = this.annotationExtractor.extractPropertyAnnotations(descriptor.getDisplayName(), bean);
            } catch (AnnotationExtractorException ex) {
                // Exceptions during annotation extraction are non-fatal. Perhaps we should throw them up, not sure.
                Logger.getLogger(DefaultClazzBuilderImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
            if (annotations != null && !annotations.isEmpty()) {
                Property property = new Property();
                property.setType(this.getTypeMapper().getType(descriptor.getPropertyType()));
                for (Annotation annotation : annotations) {
                    property.addConstraint(this.getConstraintExtractor().getConstraint(annotation));
                }
                clazz.addProperty(property);
            }
        }
        return clazz;
    }

    public AnnotationExtractor getAnnotationExtractor() {
        return annotationExtractor;
    }

    public void setAnnotationExtractor(AnnotationExtractor annotationExtractor) {
        this.annotationExtractor = annotationExtractor;
    }

    public ConstraintExtractor getConstraintExtractor() {
        return constraintExtractor;
    }

    public void setConstraintExtractor(ConstraintExtractor constraintExtractor) {
        this.constraintExtractor = constraintExtractor;
    }
        public TypeMapper getTypeMapper() {
        return typeMapper;
    }

    public void setTypeMapper(TypeMapper typeMapper) {
        this.typeMapper = typeMapper;
    }
}
